﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using LightPersist.Exceptions;

namespace LightPersist.Storage
{
	public class InmemoryStorage : BaseStorage
	{
		public InmemoryStorage() {}

		public InmemoryStorage(string connectionString) :base(connectionString) {}

		private readonly Dictionary<Guid, ObjectState> _idToObjectMap = new Dictionary<Guid, ObjectState>();

		public override void CommitRemove(ObjectState obj)
		{
			// Trace.WriteLine("IMS: REMOVE: " + obj.Identity);
			if (_idToObjectMap.ContainsKey(obj.Identity))
			{
				_idToObjectMap.Remove(obj.Identity);
			}
			else
			{
				throw new StorageException(StrErrObjDoesNotExists);
			}
		}

		public override void CommitUpdate(ObjectState obj)
		{
			// Trace.WriteLine("IMS: UPDATE: " + obj.Identity.ToStringDebug());
			if (!_idToObjectMap.ContainsKey(obj.Identity))
			{
				throw new StorageException(StrErrObjDoesNotExists);
			}
			var newState = new ObjectState();
			_idToObjectMap[obj.Identity] = newState;
			Copy(obj, newState);
		}

		public override void CommitInsert(ObjectState obj)
		{
			// Trace.WriteLine("IMS: INSERT: " + obj.Identity.ToStringDebug());
			if (_idToObjectMap.ContainsKey(obj.Identity))
			{
				throw new StorageException(StrErrObjAlreadyExists);
			}
			var newState = new ObjectState();
			_idToObjectMap.Add(obj.Identity, newState);
			Copy(obj, newState);
		}

		public override void LoadObjectCore(ObjectState obj)
		{
			// Trace.WriteLine("IMS: LOAD: " + obj.Identity.ToStringDebug());
			ObjectState inmem;
			if (!_idToObjectMap.TryGetValue(obj.Identity, out inmem))
			{
				throw new StorageException(StrErrObjDoesNotExists);
			}

			obj.ClassMetainfoDetected = inmem.ClassMetainfo.TypeNameFull;
			Copy(inmem, obj);
		}

		static void Copy(ObjectState from, ObjectState to)
		{
			foreach (var kvp in from.PropertiesState)
			{
				to.Set(kvp.Key, CloneUtils.CloneIfList(kvp.Value));
			}
			if (from.ClassMetainfo != null)
			{
				to.ClassMetainfo = from.ClassMetainfo;
			}
			if (from.ClassMetainfoDetected != null)
			{
				to.ClassMetainfoDetected = from.ClassMetainfoDetected;
			}
		}

		public override bool IsExistsCore(ObjectState obj)
		{
			return _idToObjectMap.ContainsKey(obj.Identity);
		}

		/// <summary>
		/// Retrieve Guids of every object in database.
		/// Useful for maintenance tasks only.
		/// </summary>
		public override IEnumerable<Guid> GetObjectIDsCore()
		{
			return _idToObjectMap.Keys;
		}
	}
}